#include <string>
#include <iostream>
#include <vector>
#include <boost/filesystem.hpp>
#include "util.hpp"
const std::string src_path="data/input";     //原生文件路径
const std::string output="data/raw_html/raw.txt/";  //存储最终过滤好的文件
//***********************错误状态********************/
enum Error_status{
    File_Add_Path_Failed,
    Parse_File_Failed,
    Save_Html_File_Failed,
    File_Path_Not_Exist
};
//所需内容的结构
typedef struct Obj_html{
    std::string title;      //文件内容的标题
    std::string content;    //文件的内容
    std::string url;        //html文件在boost官网中的链接
}OBJ;

//给每个html文件添加路径
bool File_Add_Path(const std::string&src_path,std::vector<std::string>*file_list);
//对每个文件进行解析，提取所需的内容
bool Parse_Html(std::vector<std::string>&file_lis,std::vector<OBJ>*results);
//把解析好的html文件，保存在output="data/raw_html/raw.txt/"
bool Save_Html(std::vector<OBJ>&results, const std::string&output);
int main()
{
    //给每个html文件添加路径
    std::vector<std::string>file_list;  //存储每个html文件的路径
    if(!File_Add_Path(src_path,&file_list))
    {
            std::cerr<<"Add file path failed !"<<std::endl;
            return  File_Add_Path_Failed;
    }

    //对每个文件进行解析，提取所需的内容
    std::vector<OBJ>results;
    if(!Parse_Html(file_list,&results))
    {
            std::cerr<<"Parse file failed !"<<std::endl;
            return Parse_File_Failed;
    }

    //把解析好的html文件，保存在output="data/raw_html/raw.txt/"
    if(!Save_Html(results,output))
    {
        std::cerr<<"Save html-file failed !"<<std::endl;
        return  Save_Html_File_Failed;
    }
    return 0;
}

//给每个html文件添加路径
bool File_Add_Path(const std::string&src_path,std::vector<std::string>*file_list)
{
    namespace fs=boost::filesystem;     //对boost里面的filesystem命名空间起别名，防止代码冗
    fs::path root_path(src_path);   //创建根路径对象，递归式遍历文件
    if(!fs::exists(root_path))
    {
        std::cerr<<"file path not exist !"<<std::endl;
        return File_Path_Not_Exist;
    }
    //创建空的迭代器
    fs::recursive_directory_iterator end;
    for(fs::recursive_directory_iterator item(root_path);item!=end;item++)
    {
        //判断是否为普通的文件
        if(!fs::is_regular_file(*item))
            continue;
        //判断是否是html文件
        if(item->path().extension()!=".html")
            continue;
        //走到这里,html文件已经被过滤出来了
        file_list->push_back(item->path().string());    //存储每一个html文件的路径
        
        //Debug测试
        //std::cout<<item->path().string()<<std::endl;
    }
    return true;
}

//******************************提取html文件到OBJ的三个属性函数***********************************************/
        //获取title
bool Html_title(std::string&results,std::string*title)
{
    auto begin=results.find("<title>");
    if(begin==std::string::npos)
    {
        std::cerr<<"find <title> failed !"<<std::endl;
        return false;
    }
    auto end=results.find("</title>");
    if(end==std::string::npos)
    {
        std::cerr<<"find </title> failed !"<<std::endl;
        return false;
    }
    size_t len=std::string("<title>").size();
    begin+=len;
    if(begin>end)
        return false;
    *title=results.substr(begin,end-begin); //获取title里面的内容
    return true;
}
        //获取content
bool Html_content(std::string&results,std::string*content)
{
    //制定字符的状态机
    enum status{
        LABEL,
        CONTENT
    };
    enum status s=LABEL;   //先假设字符的状态
    //去标签的字符状态机主体
    for(auto&c:results) //获取一个个字符
    {
        switch (s)
        {
        case LABEL:
            if(c=='>') 
                s=CONTENT;
            break;
        case CONTENT:
            if(c=='<')
                s=LABEL;
            else
            {
                if(c=='\n') c=' ';      //html文件中的\n不需要，\n用来分隔每个html文件,html内部之间用\3进行分隔
                content->push_back(c);
            }
            break;
        default:
            break;
        }
    }
    return true;
}
        //获取url
bool Html_url(std::string&file,std::string*url)
{
    const std::string head_url= "https://www.boost.org/doc/libs/1_85_0/doc/html";
    const std::string tail_url=file.substr(src_path.size());
    *url=head_url+tail_url;
    return true;
}
 
//************************************************************************************************/

//对每个文件进行解析，提取所需的内容
bool Parse_Html(std::vector<std::string>&file_lis,std::vector<OBJ>*results)
{
    for(auto&elm:file_lis)
    {
        //读取read文件
        std::string result;
        if(!util::Parse::ReadFile(elm,&result))
            continue;
        //results里面的html文件进行title,content,url的解析
        OBJ obj_file;
        //获取title
        if(!Html_title(result,&obj_file.title))
            continue;
        //获取content
        if(!Html_content(result,&obj_file.content))
            continue;
        //获取url
        if(!Html_url(elm,&obj_file.url))
            continue;
        results->push_back(std::move(obj_file));    //使用move把obj_file转为右值，底层会移动构造，提高效率
    }
    return true;
}
//把解析好的html文件，保存在output="data/raw_html/raw.txt/"
bool Save_Html(std::vector<OBJ>&results, const std::string&output)
{
    //保存在raw.txt里面的文件格式：title \3 content \3 url \n title1 \3 content1 \3 url1 \n……
    #define SEP '\3'    //定义分隔符
    //以二进制的方式进行写入文件
    std::ofstream out(output,std::ios::out|std::ios::binary);
    if(!out.is_open())
    {
        std::cerr<<"out file_open failed !"<<std::endl; //打开失败，直接不玩了，退出
        return false;
    }
    for(auto&obj:results)
    {
        std::string obj_string=obj.title+SEP+obj.content+SEP+obj.url+'\n';
        out.write(obj_string.c_str(),obj_string.size());
    }
    out.close();
    return true;
}